package com.xiaode.interceptor;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.jfinal.aop.Interceptor;
import com.jfinal.aop.Invocation;
import com.jfinal.core.Controller;
import com.jfinal.kit.Kv;
import com.jfinal.kit.Ret;
import com.jfinal.kit.ThreadPoolKit;
import com.jfinal.plugin.activerecord.Db;
import com.jfinal.plugin.activerecord.Record;
import com.jfinal.plugin.redis.Redis;
import com.jfinal.render.JsonRender;
import com.jfinal.render.Render;
import com.xiaode.common.UserTokenManager;
import com.xiaode.common.anotation.Authority;
import com.xiaode.common.constant.Const;
import com.xiaode.common.model.Admin;
import com.xiaode.common.model.dto.log.AdminLogDTO;
import com.xiaode.exce.EnumError;
import com.xiaode.plugin.influx.InfluxDbKit;

import javax.servlet.http.HttpServletRequest;
import java.lang.reflect.Method;
import java.util.List;
import java.util.Map;

/**
 * 此时已经登录 后台授权拦截器
 */
public class AdminAuthInterceptor implements Interceptor {

    @Override
    public void intercept(Invocation inv) {
        Controller c = inv.getController();
		String token = c.getHeader("token");
		if (StrUtil.isBlank(token)) {
			c.renderJson(Ret.fail().set("error", EnumError.APP_USER_TOKEN_ERROR.getObj()));
			return;
		}
		String tokenInfo = UserTokenManager.getInfo(token);
		if (StrUtil.isBlank(tokenInfo)) {
			c.renderJson(Ret.fail().set("error", EnumError.APP_USER_TOKEN_ERROR.getObj()));
			return;
		}
		JSONObject tokenInfoJ = JSONUtil.parseObj(tokenInfo);
		Integer accountId = tokenInfoJ.getInt("accountId");
		Integer userType = tokenInfoJ.getInt("userType");
		String account = tokenInfoJ.getStr("account");
		Integer userId = tokenInfoJ.getInt("userId");
		
		
		Boolean CanLoginAdmin = tokenInfoJ.getBool("canLoginAdmin");
		if(userType != Const.UserType.admin) {
			c.renderJson(Ret.fail().set("error", EnumError.AUTHORITY_NULL.getObj()));
			return;
		}
		if(!CanLoginAdmin) {
			c.renderJson(Ret.fail().set("error", EnumError.AUTHORITY_NULL.getObj()));
			return;
		}
        Boolean haveAccount = Redis.use().exists(Const.user.loginAdmin + accountId);
        if (!haveAccount) {
            c.renderJson(Ret.fail().set("error", EnumError.APP_USER_TOKEN_ERROR.getObj()));
            return;
        }
        Admin admin = Redis.use().get(Const.user.loginAdmin + accountId);
        if (BeanUtil.isEmpty(admin)) {
            c.renderJson(Ret.fail().set("error", EnumError.ACCOUNT_NO.getObj()));
            return;
        }
        
        String roleIds = admin.getRoleIds();

        Method method = inv.getMethod();
        if (!inv.getActionKey().startsWith("/aLogin") && !inv.getActionKey().startsWith("/aUser") && !inv.getActionKey().startsWith("/aStatistics") && !inv.getActionKey().equals("/authority/options")) {
            List<Integer> roleList = JSONUtil.toList(roleIds, Integer.class);
            Authority authority = method.getAnnotation(Authority.class);// 获取接口所需要的权限
            String permission = authority.permission();// 获取接口所需要的权限参数":"
            
            if (StrUtil.isNotBlank(permission)) {
                try {
                    List<String> authoritys = admin.get("authoritys");
                    if (authoritys == null){
                        c.renderJson(Ret.fail().set("error", EnumError.AUTHORITY_NOT_EXIT_ADMIN.getObj()));
                        return;
                    }
                    boolean b = false;
                    for (String auth : authoritys) {
                        if (StrUtil.equals(auth, "*")) {
                            // 获取用户角色,判断角色的只读权限
                            int authorityType = authority.type();
                            //判断是否拥有编辑权限
                            if (authorityType == 2) {
                                Kv kv = Kv.by("roleIds", roleList).set("permission", permission);
                                Record record = Db.template("adminAuthIntercept", kv).findFirst();
                                if (record == null) {
                                    c.renderJson(Ret.fail().set("error", EnumError.NOT_HAVE_AUTHORITY.getObj()));
                                    return;
                                }
                            }

                            b = true;
                            break;
                        }
                        if (StrUtil.equals(auth, permission)) {
                            // 获取用户角色,判断角色的只读权限
                            int authorityType = authority.type();
                            //判断是否拥有编辑权限
                            if (authorityType == 2) {
                                Kv kv = Kv.by("roleIds", roleList).set("permission", permission);
                                Record record = Db.template("adminAuthIntercept", kv).findFirst();
                                if (record == null) {
                                    c.renderJson(Ret.fail().set("error", EnumError.NOT_HAVE_AUTHORITY.getObj()));
                                    return;
                                }
                            }
                            b = true;
                            break;
                        }
                    }
                    if (!b) {
                        c.renderJson(Ret.fail().set("error", EnumError.NOT_HAVE_AUTHORITY));
                        return;
                    }
                } catch (Exception e) {
                    e.printStackTrace();
                    c.renderJson(Ret.fail().set("error", e.getMessage()));
                    return;
                }
            }
        }
        c.setAttr("admin", admin).setAttr("accountId", accountId).setAttr("userId", userId).setAttr("userType", userType).setAttr("account", account);// 这里包含了权限
       
        inv.invoke();

        ThreadPoolKit.execute(()->{
            if (!inv.getActionKey().startsWith("/aLogin") && !inv.getActionKey().startsWith("/aUser")) {
                // 接口路径
                HttpServletRequest request = c.getRequest();
                // 客户端ip

                String remortIP = getRemortIP(request);
                Map<String, String[]> parameterMap = request.getParameterMap();
                Render re = inv.getController().getRender();
                if (re instanceof JsonRender) {
                    AdminLogDTO alog = new AdminLogDTO();
                    String JsonText = ((JsonRender) re).getJsonText();
                    JSONObject jsonObject = JSONUtil.parseObj(JsonText);
                    String state = jsonObject.getStr("state");
                    String para = JSONUtil.toJsonStr(parameterMap);
                    Authority authority = method.getAnnotation(Authority.class);
                    String authoritys = authority.permissionParentName() + authority.permissionName() + authority.permission();
                    alog.setErrorMsg(null);
                    if (state.equals("fail")) {
                        String error = jsonObject.getStr("error");
                        alog.setErrorMsg(error);
                    }
                    alog.setTimeStamp(System.currentTimeMillis() + "");
                    alog.setMethodName(inv.getMethodName());
                    alog.setPara(para);
                    alog.setRemortIP(remortIP);
                    alog.setUrl(inv.getActionKey());
                    alog.setAdminId(admin.getId() + "");
                    alog.setAuthority(authoritys);
                    alog.setState(state);
                    alog.setField("");
                    // 存入日志
                    try {
                        InfluxDbKit.insertAsyn(alog);
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                    alog = null;
                }
            }
        });

    }

    /**
     * 获取客户端ip
     */
    public String getRemortIP(HttpServletRequest request) {
        if (request.getHeader("x-forwarded-for") == null || request.getHeader("x-forwarded-for").split(",")[0].equals( "127.0.0.1")) {
            return request.getRemoteAddr();
        }
        return request.getHeader("x-forwarded-for").split(",")[0];
    }

}
